"""
微信聊天记录导出程序
实现增量式聊天记录导出，支持自动加载历史记录
基于wxauto库实现
"""

import os
import sys
import json
import time
import hashlib
from datetime import datetime, timedelta
from pathlib import Path
from wxauto import WeChat


class ChatExporter:
    def __init__(self, export_dir="chat_exports"):
        """
        初始化聊天记录导出器
        
        Args:
            export_dir (str): 导出文件存储目录
        """
        self.wx = WeChat()
        self.export_dir = Path(export_dir)
        self.export_dir.mkdir(exist_ok=True)
        
    def export_chat_history(self, chat_name="文件传输助手", load_all_history=True):
        """
        导出指定聊天的记录
        
        Args:
            chat_name (str): 聊天对象名称，默认为"文件传输助手"
            load_all_history (bool): 是否自动加载所有历史记录
        """
        print(f"开始导出聊天记录: {chat_name}")
        
        # 切换到聊天页面
        self.wx.SwitchToChat()
        time.sleep(1)
        
        # 查找并切换到目标聊天
        if not self._switch_to_chat(chat_name):
            print(f"❌ 无法找到聊天: {chat_name}")
            return False
        
        # 确认当前聊天窗口
        chat_info = self.wx.ChatInfo()
        current_chat = chat_info.get('chat_name', '')
        if current_chat != chat_name:
            print(f"❌ 切换聊天失败，当前: {current_chat}，目标: {chat_name}")
            return False
        
        print(f"✅ 已切换到聊天: {current_chat}")
        
        # 读取上次导出的最后记录
        last_message_hash = self._get_last_exported_message(chat_name)
        
        # 如果需要加载全部历史记录，自动点击"查看更多消息"
        if load_all_history:
            self._load_all_history()
        
        # 获取当前所有消息
        messages = self.wx.GetAllMessage()
        print(f"📝 获取到 {len(messages)} 条消息")
        
        # 如果有上次记录，找到增量消息
        if last_message_hash:
            messages = self._get_incremental_messages(messages, last_message_hash)
            print(f"📝 增量消息: {len(messages)} 条")
        
        if not messages:
            print("💡 没有新消息需要导出")
            return True
        
        # 导出消息到文件
        export_file = self._create_export_file(chat_name)
        self._write_messages_to_file(messages, export_file, chat_info)
        
        print(f"✅ 导出完成: {export_file}")
        return True
    
    def _switch_to_chat(self, chat_name):
        """
        切换到指定聊天窗口
        
        Args:
            chat_name (str): 聊天名称
            
        Returns:
            bool: 是否成功切换
        """
        # 先从会话列表中查找
        sessions = self.wx.GetSession()
        print(f"🔍 在会话列表中查找: {chat_name}")
        
        for session in sessions:
            if session.name == chat_name:
                print(f"✅ 在会话列表中找到: {chat_name}")
                session.click()
                time.sleep(1)
                return True
        
        # 如果会话列表中没有，尝试搜索
        print(f"🔍 在会话列表中未找到，尝试搜索: {chat_name}")
        search_results = self.wx.SessionBox.search(chat_name)
        
        if search_results:
            for result in search_results:
                if chat_name in result.get_all_text():
                    print(f"✅ 搜索到: {chat_name}")
                    result.click()
                    time.sleep(1)
                    return True
        
        return False
    
    def _load_all_history(self):
        """
        自动点击"查看更多消息"来加载历史记录
        限制只加载最近3天的消息
        """
        print("🔄 开始加载历史消息（限制3天内）...")
        load_count = 0
        max_loads = 20  # 限制最大加载次数，防止加载过多
        
        # 计算3天前的时间
        three_days_ago = datetime.now() - timedelta(days=3)
        print(f"📅 时间限制: {three_days_ago.strftime('%Y-%m-%d %H:%M:%S')} 之后的消息")
        
        while load_count < max_loads:
            try:
                # 尝试加载更多消息
                result = self.wx.LoadMoreMessage()
                
                if result:  # 成功加载更多消息
                    load_count += 1
                    print(f"📥 已加载更多消息 ({load_count}/{max_loads} 次)")
                    time.sleep(0.5)  # 等待消息加载
                    
                    # 每5次加载检查一次时间限制，避免频繁调用GetAllMessage
                    if load_count % 5 == 0:
                        try:
                            messages = self.wx.GetAllMessage()
                            if messages:
                                # 检查最早消息的时间
                                earliest_msg = messages[0]  # 第一条是最早的消息
                                earliest_time_str = self._extract_message_time(earliest_msg)
                                
                                if earliest_time_str:
                                    earliest_time = self._parse_message_time(earliest_time_str)
                                    if earliest_time and earliest_time < three_days_ago:
                                        print(f"⏰ 已达到3天限制，最早消息时间: {earliest_time_str}")
                                        break
                        except Exception as e:
                            print(f"⚠️ 检查时间限制时出错: {e}")
                else:
                    # 无法继续加载，说明已到达最早的消息
                    print("✅ 已加载所有可用历史消息")
                    break
                    
            except Exception as e:
                print(f"⚠️ 加载历史消息时出错: {e}")
                break
        
        if load_count >= max_loads:
            print(f"✅ 已达到加载次数限制 ({max_loads} 次)")
        
        # 加载完成后等待一下，让界面稳定
        time.sleep(1)
    
    def _extract_message_time(self, msg):
        """
        提取消息的时间字符串
        
        Args:
            msg: 消息对象
            
        Returns:
            str: 时间字符串，如果无法提取则返回None
        """
        try:
            # 打印消息对象的属性，用于调试
            debug_info = []
            if hasattr(msg, '__dict__'):
                for key, value in msg.__dict__.items():
                    debug_info.append(f"{key}: {value}")
            
            # 尝试从消息对象获取时间
            if hasattr(msg, 'time') and msg.time:
                return msg.time
            
            # 如果消息对象没有time属性，尝试从info中获取
            if hasattr(msg, 'info') and isinstance(msg.info, dict):
                time_str = msg.info.get('time')
                if time_str:
                    return time_str
            
            # 尝试其他可能的时间属性
            for attr in ['timestamp', 'datetime', 'create_time', 'send_time']:
                if hasattr(msg, attr):
                    value = getattr(msg, attr)
                    if value:
                        return str(value)
            
            # 如果第一次调用，打印调试信息
            if not hasattr(self, '_debug_printed'):
                print(f"🔍 消息对象属性调试: {debug_info[:3]}...")  # 只显示前3个属性
                self._debug_printed = True
            
            return None
            
        except Exception as e:
            return None
    
    def _parse_message_time(self, time_str):
        """
        解析消息时间字符串为datetime对象
        
        Args:
            time_str (str): 时间字符串
            
        Returns:
            datetime: 解析后的时间对象，如果解析失败则返回None
        """
        if not time_str:
            return None
        
        # 常见的时间格式
        time_formats = [
            '%Y-%m-%d %H:%M:%S',
            '%Y/%m/%d %H:%M:%S', 
            '%m-%d %H:%M',
            '%m/%d %H:%M',
            '%H:%M:%S',
            '%H:%M'
        ]
        
        try:
            for fmt in time_formats:
                try:
                    parsed_time = datetime.strptime(time_str.strip(), fmt)
                    
                    # 如果格式不包含年份，使用当前年份
                    if '%Y' not in fmt:
                        current_year = datetime.now().year
                        parsed_time = parsed_time.replace(year=current_year)
                    
                    # 如果格式不包含日期，使用当前日期
                    if '%m' not in fmt and '%d' not in fmt:
                        current_date = datetime.now().date()
                        parsed_time = datetime.combine(current_date, parsed_time.time())
                    
                    return parsed_time
                    
                except ValueError:
                    continue
            
            return None
            
        except Exception as e:
            return None
    
    def _get_last_exported_message(self, chat_name):
        """
        获取上次导出的最后一条消息的哈希值
        
        Args:
            chat_name (str): 聊天名称
            
        Returns:
            str: 最后一条消息的哈希值，如果没有则返回None
        """
        # 查找最新的导出文件
        safe_name = self._safe_filename(chat_name)
        pattern = f"{safe_name}_*.txt"
        
        export_files = list(self.export_dir.glob(pattern))
        if not export_files:
            print("💡 未找到历史导出文件，将导出全部消息")
            return None
        
        # 找到最新的导出文件
        latest_file = max(export_files, key=lambda x: x.stat().st_mtime)
        print(f"📖 找到最新导出文件: {latest_file.name}")
        
        # 读取最后一条记录的哈希值
        try:
            with open(latest_file, 'r', encoding='utf-8') as f:
                lines = f.readlines()
                
            # 从后往前找最后一条消息记录
            for line in reversed(lines):
                line = line.strip()
                if line.startswith('[') and '] ' in line and '：' in line:
                    # 计算这条消息的哈希值
                    message_hash = hashlib.md5(line.encode('utf-8')).hexdigest()
                    print(f"📌 上次导出最后消息哈希: {message_hash[:8]}...")
                    return message_hash
                    
        except Exception as e:
            print(f"⚠️ 读取历史文件时出错: {e}")
        
        return None
    
    def _get_incremental_messages(self, messages, last_message_hash):
        """
        获取增量消息（从上次导出后的新消息）
        
        Args:
            messages (list): 所有消息列表
            last_message_hash (str): 上次导出的最后消息哈希值
            
        Returns:
            list: 增量消息列表
        """
        if not last_message_hash:
            return messages
        
        incremental_messages = []
        found_last_position = False
        
        # 从后往前遍历消息，找到上次的位置
        for i, msg in enumerate(messages):
            # 构建消息行用于哈希计算
            msg_time = self._extract_message_time(msg) or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            message_line = f"[{msg_time}] {msg.sender}：{msg.content}"
            message_hash = hashlib.md5(message_line.encode('utf-8')).hexdigest()
            
            if message_hash == last_message_hash:
                # 找到上次导出的最后位置，返回之后的消息
                found_last_position = True
                incremental_messages = messages[i + 1:]
                print(f"📍 找到上次导出位置，获取后续 {len(incremental_messages)} 条新消息")
                break
        
        if not found_last_position:
            print("⚠️ 未找到上次导出位置，将导出所有消息")
            return messages
        
        return incremental_messages
    
    def _create_export_file(self, chat_name):
        """
        创建导出文件
        
        Args:
            chat_name (str): 聊天名称
            
        Returns:
            Path: 导出文件路径
        """
        safe_name = self._safe_filename(chat_name)
        date_str = datetime.now().strftime('%Y%m%d')
        timestamp = datetime.now().strftime('%H%M%S')
        
        filename = f"{date_str}_{safe_name}_{timestamp}.txt"
        return self.export_dir / filename
    
    def _safe_filename(self, filename):
        """
        生成安全的文件名
        
        Args:
            filename (str): 原始文件名
            
        Returns:
            str: 安全的文件名
        """
        return "".join(c for c in filename if c.isalnum() or c in (' ', '-', '_', '(', ')')).strip()
    
    def _sort_messages_by_time(self, messages):
        """
        按时间排序消息
        
        Args:
            messages (list): 消息列表
            
        Returns:
            list: 按时间排序后的消息列表
        """
        def get_message_datetime(msg):
            """获取消息的datetime对象，用于排序"""
            time_str = self._extract_message_time(msg)
            if time_str:
                parsed_time = self._parse_message_time(time_str)
                if parsed_time:
                    return parsed_time
            
            # 如果无法解析时间，返回一个很早的时间作为默认值
            return datetime(1970, 1, 1)
        
        try:
            # 按时间排序，从早到晚
            sorted_messages = sorted(messages, key=get_message_datetime)
            print(f"📅 消息已按时间排序：从 {len(sorted_messages)} 条消息中排序完成")
            return sorted_messages
        except Exception as e:
            print(f"⚠️ 消息排序失败，使用原始顺序: {e}")
            return messages
    
    def _write_messages_to_file(self, messages, export_file, chat_info):
        """
        将消息写入文件
        
        Args:
            messages (list): 消息列表
            export_file (Path): 导出文件路径
            chat_info (dict): 聊天信息
        """
        # 按时间排序消息
        # sorted_messages = self._sort_messages_by_time(messages)
        
        with open(export_file, 'w', encoding='utf-8') as f:
            # 写入文件头信息
            f.write(f"聊天对象: {chat_info.get('chat_name', '未知')}\n")
            f.write(f"聊天类型: {chat_info.get('chat_type', '未知')}\n")
            f.write(f"导出时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write(f"消息数量: {len(messages)}\n")
            f.write("=" * 50 + "\n\n")
            
            # 写入消息记录 
            for msg in messages:
                try:
                    # 获取消息时间
                    msg_time = self._extract_message_time(msg)
                    if not msg_time:
                        # 如果无法提取时间，显示为"未知时间"
                        msg_time = "未知时间"
                    
                    # 格式化消息
                    message_line = f"[{msg_time}] {msg.sender}：{msg.content}\n"
                    f.write(message_line)
                    
                except Exception as e:
                    # 如果处理某条消息出错，记录错误但继续处理其他消息
                    error_line = f"[错误] 处理消息时出错: {str(e)}\n"
                    f.write(error_line)
            
            # 写入结尾信息
            f.write(f"\n{'=' * 50}\n")
            f.write(f"导出完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write(f"总计消息数: {len(messages)}")


def main():
    """
    主函数 - 程序入口
    """
    print("📤 微信聊天记录导出程序")
    print("=" * 50)
    
    # 获取命令行参数
    chat_name = "文件传输助手"  # 默认值
    
    if len(sys.argv) > 1:
        chat_name = sys.argv[1]
        print(f"📝 指定导出聊天: {chat_name}")
    else:
        print(f"📝 使用默认聊天: {chat_name}")
        print("💡 可使用命令: python chat_exporter.py '群名或好友名'")
    
    print(f"📁 导出文件将保存到: ./chat_exports/")
    print()
    
    # 创建导出器实例
    exporter = ChatExporter()
    
    try:
        # 开始导出
        success = exporter.export_chat_history(chat_name)
        
        if success:
            print("\n✅ 导出完成!")
        else:
            print("\n❌ 导出失败!")
            
    except Exception as e:
        print(f"\n❌ 程序异常: {e}")
        import traceback
        traceback.print_exc()
    
    finally:
        print("\n🔚 程序结束")


if __name__ == "__main__":
    main()